package com.zongtui.fourinone.file;

import com.zongtui.fourinone.utils.log.LogUtil;
import com.zongtui.fourinone.obj.ObjectBytes;
import com.zongtui.fourinone.base.PoolExector;
import com.zongtui.fourinone.exception.FileException;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.reflect.Method;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

public class FileAdapter extends File {
    private RandomAccessFile raf = null;
    private FileChannel fc = null;
    private ByteBuffer mbread = null, mbwrite = null;

    public static final short[] ConstBit = new short[]{0, 1 << 1, 1 << 2, 1 << 3, 3 << 1, 5 << 1, 6 << 1, 7 << 1, 1};

    public static long k(long num) {
        return 0x400 * num;
    }

    public static long m(long num) {
        return 0x400 * k(num);
    }

    public static long g(long num) {
        return 0x400 * m(num);
    }

    public FileAdapter(String filePath) {
        super(filePath);
        //fl = new File(filePath);
    }

    public FileAdapter(String parentPath, String filePath) {
        super(parentPath, filePath);
        //fl = parentPath!=null?new File(parentPath, filePath):new File(filePath);
    }


    FileLock flk = null;

    public boolean readLock() {
        return readLock(0L, Long.MAX_VALUE);
    }

    public boolean readLock(long beginIndex, long bytesNum) {
        return setLock("r", 0L, Long.MAX_VALUE, true);
    }

    public boolean writeLock() {
        return writeLock(0L, Long.MAX_VALUE);
    }

    public boolean writeLock(long beginIndex, long bytesNum) {
        if (!this.exists())
            createFile(this.getPath());
        return setLock("rw", 0L, Long.MAX_VALUE, false);
    }

    boolean setLock(String rw, long beginIndex, long bytesNum, boolean s) {
        if (!this.exists())
            return false;
        try {
            raf = new RandomAccessFile(this, rw);
            fc = raf.getChannel();
            flk = fc.lock(beginIndex, bytesNum, s);
        } catch (OverlappingFileLockException oe) {
            LogUtil.warn("[SetLock]", "[No effect]", "the region has already been locked");
            return false;
        } catch (Exception e) {
            LogUtil.info("[SetLock]", "[No effect]", e);
            return false;
        }
        return true;
    }

    public boolean releaseLock() {
        if (!this.exists() || flk == null)
            return false;
        try {
            flk.release();
        } catch (Exception e) {
            LogUtil.info("[ReleaseLock]", "[No effect]", e);
            return false;
        }
        return true;
    }

    public static ByteReadParser getByteReadParser(byte[] array) {
        if (array == null)
            array = new byte[0];
        FileAdapter fa = new FileAdapter("");
        fa.mbread = ByteBuffer.wrap(array);
        return fa.getReader(Long.MIN_VALUE, Long.MAX_VALUE);
    }

    public static ByteReadParser getByteReadParser() {
        return getByteReadParser(null);
    }

    public interface ByteReadParser {
        public byte[] read(int totalnum);

        public byte[] readLine();

        public byte[] read(byte[] split);

        public byte[] readLast(byte[] split);

        public void jump(int num);

        public int getReadIndex();

        public short readShort();

        public int readInt();

        public long readLong();

        public float readFloat();

        public double readDouble();

        public Date readDate();

        public String readString(int length);

        public byte[] readCharsBytes(int length);

        public String readChars(int length);

        public Object readObject(int length);

        public ByteReadParser reset(byte[] array);

        public boolean reading();
    }

    public interface ByteReadAdapter extends ByteReadParser, FileBatch.TryByteReadAdapter {
        public byte[] readAll();

        public byte[] readAllSafety() throws FileException;
    }

    public interface IntReadAdapter extends FileBatch.TryIntReadAdapter {
        public int[] readIntAll();

        public int[] readIntAllSafety() throws FileException;

        public int[] readInt(int totalnum);

        public int readInt();

        public List<Integer> readListIntAll();

        public List<Integer> readListInt(int totalnum);
    }

    public interface ReadAdapter extends ByteReadAdapter, IntReadAdapter {
    }

    private boolean initRead(long beginIndex, long bytesNum) {
        if (beginIndex == Long.MIN_VALUE && bytesNum == Long.MAX_VALUE)
            return true;

        try {
            if (raf == null) {
                raf = new RandomAccessFile(this, "r");//fl
                fc = raf.getChannel();
            }

            long readnum = Math.min(this.length() - beginIndex, bytesNum);//fl
            //if(readnum==0)return false;
            mbread = fc.map(MapMode.READ_ONLY, beginIndex, readnum);
        } catch (Exception e) {
            //System.out.println(e);
            LogUtil.info("[FileAdapter]", "[ReadAdapter]", e.getMessage());
            return false;
        }
        return true;
    }

    public interface IntWriteAdapter extends FileBatch.TryIntWriteAdapter {
        public int writeInt(int[] its);

        public int writeIntSafety(int[] its) throws FileException;

        public int writeListInt(List<Integer> ls);
    }

    public interface ByteWriteAdapter extends FileBatch.TryByteWriteAdapter {
        public int write(byte[] bytes);

        public int writeSafety(byte[] bytes) throws FileException;
    }

    public interface WriteAdapter extends ByteWriteAdapter, IntWriteAdapter {
    }

    class NameFilter implements FilenameFilter {
        private String namestr;
        private boolean onlyFile = false;

        public NameFilter(String namestr, boolean onlyFile) {
            this.namestr = namestr;
            this.onlyFile = onlyFile;
        }

        public boolean accept(File dir, String name) {
            if (name.startsWith(namestr)) {
                if (onlyFile) {
                    File dirfile = new File(dir, name);
                    return dirfile.isFile();
                } else {
                    return true;
                }
            } else {
                return false;
            }
        }
    }

    public interface ByteWriteParser {
        public ByteWriteParser writeBytes(byte[] bts);

        public ByteWriteParser writeShort(short n);

        public ByteWriteParser writeInt(int n);

        public ByteWriteParser writeDouble(double n);

        public ByteWriteParser writeLong(long n);

        public ByteWriteParser writeFloat(float n);

        public ByteWriteParser writeDate(Date time);

        public ByteWriteParser writeString(String n);

        public ByteWriteParser writeCharsBytes(byte[] bts);

        public ByteWriteParser writeChars(String n);

        public ByteWriteParser writeObject(Object n);

        public int getBytesLength();

        public byte[] getBytes();

        public ByteWriteParser reset();

        public ByteWriteParser reset(int size);
    }

    public static ByteWriteParser getByteWriteParser() {
        return getByteWriteParser((int) k(512));
    }

    public static ByteWriteParser getByteWriteParser(int size) {
        FileAdapter fa = new FileAdapter("");
        return fa.getByteParserWriter(size);
    }

    public ByteWriteParser getByteParserWriter(final int size) {
        return size <= 0 ? null : new ByteWriteParser() {
            private int bytesLength = 0;

            {
                reset(size);
            }

            public ByteWriteParser writeBytes(byte[] bts) {
                if (bts != null && bts.length > 0) {
                    autoBuffer(bts.length);
                    mbwrite.put(bts);
                    bytesLength += bts.length;
                }
                return this;
            }

            public ByteWriteParser writeShort(short n) {
                autoBuffer(ConstBit[1]);
                mbwrite.putShort(n);
                bytesLength += ConstBit[1];
                return this;
            }

            public ByteWriteParser writeInt(int n) {
                autoBuffer(ConstBit[2]);
                mbwrite.putInt(n);
                bytesLength += ConstBit[2];
                return this;
            }

            public ByteWriteParser writeDouble(double n) {
                autoBuffer(ConstBit[3]);
                mbwrite.putDouble(n);
                bytesLength += ConstBit[3];
                return this;
            }

            public ByteWriteParser writeLong(long n) {
                autoBuffer(ConstBit[3]);
                mbwrite.putLong(n);
                bytesLength += ConstBit[3];
                return this;
            }

            public ByteWriteParser writeFloat(float n) {
                autoBuffer(ConstBit[2]);
                mbwrite.putFloat(n);
                bytesLength += ConstBit[2];
                return this;
            }

            public ByteWriteParser writeDate(Date time) {
                return writeLong(time.getTime());
            }

            public ByteWriteParser writeString(String n) {
                return writeBytes(n.getBytes());
            }

            //ObjectBytes objectBytes = new ObjectBytes();
            public ByteWriteParser writeCharsBytes(byte[] bts) {
                return writeBytes(ObjectBytes.getCharSequence(bts));
            }

            public ByteWriteParser writeChars(String n) {
                return writeCharsBytes(n.getBytes());
            }

            public ByteWriteParser writeObject(Object n) {
                return writeBytes(ObjectBytes.toBytes(n));
            }

            public int getBytesLength() {
                return bytesLength;
            }

            public byte[] getBytes() {
                byte[] btsnew = new byte[bytesLength];
                System.arraycopy(mbwrite.array(), 0, btsnew, 0, bytesLength);
                return btsnew;
            }

            public ByteWriteParser reset() {
                //return reset(size);
                mbwrite.clear();
                bytesLength = 0;
                return this;
            }

            public ByteWriteParser reset(int newsize) {
                mbwrite = ByteBuffer.wrap(new byte[newsize]);
                bytesLength = 0;
                return this;
            }

            private void autoBuffer(int length) {
                while (mbwrite.remaining() < length) {
                    byte[] btsnew = new byte[mbwrite.capacity() + size];
                    System.arraycopy(mbwrite.array(), 0, btsnew, 0, bytesLength);
                    mbwrite = ByteBuffer.wrap(btsnew, bytesLength, btsnew.length - bytesLength);
                }
            }
        };
    }

    //----------------
    private void initWrite() {
        try {
            if (raf == null) {
                if (!this.exists())//fl
                    createFile(this.getPath());//fl
                raf = new RandomAccessFile(this, "rw");//fl
                fc = raf.getChannel();
            }
        } catch (Exception e) {
            LogUtil.info("[FileAdapter]", "[WriteAdapter]", e.getMessage());
        }
    }

    public ByteReadAdapter getByteReader() {
        return getReader();
    }

    public IntReadAdapter getIntReader() {
        return getReader();
    }

    public ReadAdapter getReader() {
        return getReader(0, this.length());//byte.length
    }

    public ByteReadAdapter getByteReader(long beginIndex, long bytesNum) {
        return getReader(beginIndex, bytesNum);
    }

    public IntReadAdapter getIntReader(long beginIndex, long intNum) {
        return getReader(beginIndex * 4, intNum * 4);
    }

    public ReadAdapter getReader(final long beginIndex, final long bytesNum) {
        if (!initRead(beginIndex, bytesNum))
            return null;
        else return new ReadAdapter() {
            public void jump(int num) {
                int jumpnum = Math.min(mbread.remaining(), num);
                mbread.position(getReadIndex() + jumpnum);
            }

            public int getReadIndex() {
                return mbread.position();
            }

            public byte[] readAll() {
                return read((int) Math.min(bytesNum, Integer.MAX_VALUE));
            }

            public byte[] readAllSafety() throws FileException {
                byte[] rbts = null;
                FileLock fl = null;
                try {
                    fl = fc.lock(beginIndex, bytesNum, true);
                    rbts = readAll();
                    fl.release();
                } catch (Exception ex) {
                    throw new FileException(ex);
                }
                return rbts;
            }

            public Result<byte[]> tryReadAll() {
                return tryReadAll(false);
            }

            public Result<byte[]> tryReadAllSafety() {
                return tryReadAll(true);
            }

            private Result<byte[]> tryReadAll(final boolean locked) {
                final FileResult<byte[]> fr = new FileResult<>(false);
                PoolExector.tpe().execute(new Runnable() {
                    public void run() {
                        try {
                            byte[] wh = locked ? readAllSafety() : readAll();
                            if (wh != null)
                                fr.setResult(wh);
                            fr.setReady(FileResult.READY);
                        } catch (Throwable e) {
                            LogUtil.info("tryReadAll", "exception", e);
                            //fr.status = FileResult.EXCEPTION;
                            fr.setReady(FileResult.EXCEPTION);
                        }
                    }
                });
                return fr;
            }

            public byte[] read(int totalnum) {
                int readnum = Math.min(mbread.remaining(), totalnum);
                byte[] bt = null;
                try {
                    if (readnum > 0) {
                        bt = new byte[readnum];
                        mbread.get(bt);
                    }
                } catch (Exception e) {
                    LogUtil.info("[ReadAdapter]", "[read]", e.getMessage());//
                }
                return bt;
            }

            public byte[] readLine() {
                byte[] bts = new byte[]{0xD, 0xA};
                return read(bts);
            }

            public byte[] read(byte[] split) {
                if (split == null || mbread.remaining() == 0)
                    return null;

                int i = 0, p = mbread.position(), n = 0;
                while (mbread.hasRemaining() && i < split.length) {
                    byte b = mbread.get();
                    if (b == split[i]) {
                        if (i++ == 0)
                            mbread.mark();
                    } else {
                        if (i > 0) {
                            mbread.reset();
                            i = 0;
                        }
                        n++;
                    }
                }

                if (i < split.length) {
                    n += i;
                    i = 0;
                }

                mbread.position(p);
                byte[] rbts = new byte[n];
                mbread.get(rbts);
                mbread.position(mbread.position() + i);
                return rbts;
            }

            public byte[] readLast(byte[] split) {
                byte[] bts = readAll();

                if (split == null || bts == null)
                    return null;

                int i = bts.length - 1, j = split.length - 1, m = -1;
                while (i >= 0 && j >= 0) {
                    if (bts[i--] == split[j]) {
                        if (j-- == split.length - 1)
                            m = i;
                    } else if (m > 0) {
                        i = m - 1;
                        j = split.length - 1;
                        m = -1;
                    }
                }
                return i > 0 ? Arrays.copyOf(bts, i + 1) : bts;
            }

            public int[] readIntAll() {
                return readInt((int) (bytesNum / 4));
            }

            public int[] readIntAllSafety() throws FileException {
                int[] rits = null;
                FileLock fl = null;
                try {
                    fl = fc.lock(beginIndex, bytesNum, true);
                    rits = readIntAll();
                    fl.release();
                } catch (Exception ex) {
                    throw new FileException(ex);
                }
                return rits;
            }

            public Result<int[]> tryIntReadAll() {
                return tryIntReadAll(false);
            }

            public Result<int[]> tryIntReadAllSafety() {
                return tryIntReadAll(true);
            }

            private Result<int[]> tryIntReadAll(final boolean locked) {
                final FileResult<int[]> fr = new FileResult<>(false);
                PoolExector.tpe().execute(new Runnable() {
                    public void run() {
                        try {
                            int[] wh = locked ? readIntAllSafety() : readIntAll();
                            if (wh != null)
                                fr.setResult(wh);
                            fr.setReady(FileResult.READY);
                        } catch (Throwable e) {
                            LogUtil.info("tryIntReadAll", "exception", e);
                            fr.setReady(FileResult.EXCEPTION);
                        }
                    }
                });
                return fr;
            }

            public int[] readInt(int totalnum) {
                int readnum = Math.min(mbread.remaining() / 4, totalnum);
                int[] its = null;
                if (readnum > 0) {
                    its = new int[readnum];
                    for (int i = 0; i < its.length; i++)
                        its[i] = readInt();
                }
                return its;
            }

            public List<Integer> readListIntAll() {
                return readListInt((int) (bytesNum / 4));
            }

            public List<Integer> readListInt(int totalnum) {
                int size = Math.min(mbread.remaining() / 4, totalnum);
                List<Integer> ls = null;
                if (size > 0) {
                    ls = new ArrayList<>(size);
                    for (int i = 0; i < size; i++)
                        ls.add(readInt());
                }
                return ls;
            }

            public boolean reading() {
                return mbread.hasRemaining();
            }

            public int readInt() {
                int n = 0;
                try {
                    n = mbread.getInt();
                } catch (Exception e) {
                    LogUtil.info("[ReadAdapter]", "convert int data format error", e.toString());//
                }
                return n;
            }

            public short readShort() {
                short n = 0;
                try {
                    n = mbread.getShort();
                } catch (Exception e) {
                    LogUtil.info("[ReadAdapter]", "convert short data format error", e.toString());
                }
                return n;
            }

            public long readLong() {
                long n = 0;
                try {
                    n = mbread.getLong();
                } catch (Exception e) {
                    LogUtil.info("[ReadAdapter]", "convert long data format error", e.toString());
                }
                return n;
            }

            public float readFloat() {
                float n = 0;
                try {
                    n = mbread.getFloat();
                } catch (Exception e) {
                    LogUtil.info("[ReadAdapter]", "convert float data format error", e.toString());
                }
                return n;
            }

            public double readDouble() {
                double n = 0;
                try {
                    n = mbread.getDouble();
                } catch (Exception e) {
                    LogUtil.info("[ReadAdapter]", "convert double data format error", e.toString());
                }
                return n;
            }

            public Date readDate() {
                long t = readLong();
                return t == 0 ? null : new Date(t);
            }

            public String readString(int length) {
                byte[] bts = read(length);
                return bts != null ? new String(bts) : null;
            }

            //ObjectBytes objectBytes = new ObjectBytes();
            public byte[] readCharsBytes(int length) {
                return ObjectBytes.getCharSequence(read(length));
            }

            public String readChars(int length) {
                byte[] bts = readCharsBytes(length);
                return bts != null ? new String(bts) : null;
            }

            public Object readObject(int length) {
                byte[] bts = read(length);
                return bts != null ? ObjectBytes.toObject(bts) : null;
            }

            public ByteReadParser reset(byte[] array) {
                mbread = ByteBuffer.wrap(array);
                return this;
            }
        };
    }

    public File createFile() {
        return createFile(this.getPath());
    }

    public File createDirectory() {
        return createFile(this.getPath(), false);
    }

    public File createFile(String fileUrl) {
        return createFile(fileUrl, true);
    }

    public File createFile(String fileUrl, boolean fileflag) {
        File newFile = new File(fileUrl);
        try {
            if (fileflag) {
                String parentStr = newFile.getParent();
                String fileName = newFile.getName();
                File newDir = parentStr != null ? createFile(parentStr, false) : new File("");
                File theFile = new File(newDir, fileName);
                theFile.createNewFile();
                /*if(!theFile.createNewFile())
                    System.out.println(fileUrl+" already existed!");*/
            } else {
                if (!newFile.exists())
                    newFile.mkdirs();
            }
        } catch (Exception e) {
            LogUtil.info("[FileAdapter]", "[createFile]", e.getMessage() + ":" + fileUrl);
        }
        return newFile;
    }

    public ByteWriteAdapter getByteWriter() {
        return getWriter();
    }

    public IntWriteAdapter getIntWriter() {
        return getWriter();
    }

    public WriteAdapter getWriter() {
        return getWriter(-1, -1);
    }

    public ByteWriteAdapter getByteWriter(long beginIndex, long bytesNum) {
        return getWriter(beginIndex, bytesNum);
    }

    public IntWriteAdapter getIntWriter(long beginIndex, long intNum) {
        return getWriter(beginIndex * 4, intNum * 4);
    }

    public WriteAdapter getWriter(final long beginIndex, final long bytesNum) {
        initWrite();
        final long filesize = this.length();
        return new WriteAdapter() {
            private long index, num;

            private void initIndexNum(long t) {
                index = beginIndex < 0 ? filesize : beginIndex;
                num = bytesNum < 0 ? t : bytesNum;
            }

            private void initWriteBuffer(int total) throws IOException {
                initIndexNum(total);
                mbwrite = fc.map(MapMode.READ_WRITE, index, num);
            }

            public int write(byte[] bytes) {
                int t = 0;
                try {
                    initWriteBuffer(bytes.length);
                    if (bytes.length > num)//mbread.remaining()
                        bytes = Arrays.copyOf(bytes, (int) num);
                    mbwrite.put(bytes);
                    t = bytes.length;
                } catch (Exception e) {
                    LogUtil.info("[WriteAdapter]", "[write]", e.getMessage());//
                }
                return t;
            }
			
			/*public int writeSafety(byte[] bytes) throws FileException{
				int t = 0;
				FileLock fl = null;
				try{
					initIndexNum(bytes.length);
					fl = fc.lock(index,num,false);//
					t = write(bytes);//raf.write(1);
					fl.release();//
				}catch(Exception ex){
					throw new FileException(ex);
				}
				return t;
			}*/

            public int writeSafety(byte[] bytes) throws FileException {
                return writeSafety(bytes, null);
            }

            private int writeSafety(byte[] bytes, int[] its) throws FileException {
                int t = 0;
                FileLock fl = null;
                try {
                    if (bytes != null)
                        initIndexNum(bytes.length);
                    else
                        initIndexNum(its.length * 4);
                    fl = fc.lock(index, num, false);
                    t = bytes != null ? write(bytes) : writeInt(its);
                    fl.release();
                } catch (Exception ex) {
                    throw new FileException(ex);
                }
                return t;
            }

            private int write(byte[] bytes, int[] its) {
                return bytes != null ? write(bytes) : writeInt(its);
            }

            public Result<Integer> tryWrite(byte[] bytes) {
                return tryWrite(bytes, null, false);
            }

            public Result<Integer> tryWriteSafety(byte[] bytes) {
                return tryWrite(bytes, null, true);
            }
			
			/*private Result<Integer> tryWrite(final byte[] bytes, final boolean locked)
			{
				final FileResult<Integer> fr = new FileResult<Integer>(false);
				PoolExector.tpe().execute(new Runnable(){
					public void run(){
						try{
							int bl = locked?writeSafety(bytes):write(bytes);
							fr.setResult(new Integer(bl));
							//fr.setReady(true);
							fr.setReady(FileResult.READY);
						}catch(Throwable e){
							LogUtil.info("tryWrite", "exception", e);
							//fr.status = FileResult.EXCEPTION;
							fr.setReady(FileResult.EXCEPTION);
						}
					}
				});
				return fr;
			}*/

            private Result<Integer> tryWrite(final byte[] bytes, final int[] its, final boolean locked) {
                final FileResult<Integer> fr = new FileResult<>(false);
                PoolExector.tpe().execute(new Runnable() {
                    public void run() {
                        try {
                            int bl = locked ? writeSafety(bytes, its) : write(bytes, its);
                            fr.setResult(bl);
                            //fr.setReady(true);
                            fr.setReady(FileResult.READY);
                        } catch (Throwable e) {
                            LogUtil.info("tryWrite", "exception", e);
                            //fr.status = FileResult.EXCEPTION;
                            fr.setReady(FileResult.EXCEPTION);
                        }
                    }
                });
                return fr;
            }

            public int writeInt(int[] its) {
                int i = 0;
                try {
                    initWriteBuffer(its.length * 4);
                    int wt = Math.min((int) (num / 4), its.length);
                    for (; i < wt; i++)
                        mbwrite.putInt(its[i]);
                } catch (Exception e) {
                    LogUtil.info("[WriteAdapter]", "[writeInt]", e.getMessage());
                }
                return i;
            }
			
			/*public int writeIntSafety(int[] its) throws FileException
			{
				int t = 0;
				FileLock fl = null;
				try{
					initIndexNum(its.length*4);
					fl = fc.lock(index,num,false);
					t = writeInt(its);
					fl.release();
				}catch(Exception ex){
					throw new FileException(ex);
				}
				return t;
			}*/

            public int writeIntSafety(int[] its) throws FileException {
                return writeSafety(null, its);
            }

            public Result<Integer> tryIntWrite(int[] its) {
                return tryWrite(null, its, false);
            }

            public Result<Integer> tryIntWriteSafety(int[] its) {
                return tryWrite(null, its, true);
            }
			
			/*private Result<Integer> tryIntWrite(final int[] its, final boolean locked)
			{
				final FileResult<Integer> fr = new FileResult<Integer>(false);
				PoolExector.tpe().execute(new Runnable(){
					public void run(){
						try{
							int bl = locked?writeIntSafety(its):writeInt(its);
							fr.setResult(new Integer(bl));
							fr.setReady(FileResult.READY);
						}catch(Throwable e){
							LogUtil.info("tryIntWrite", "exception", e);
							fr.setReady(FileResult.EXCEPTION);
						}
					}
				});
				return fr;
			}*/

            public int writeListInt(List<Integer> ls) {
                int i = 0;
                try {
                    initWriteBuffer(ls.size() * 4);
                    int wt = Math.min((int) (num / 4), ls.size());
                    for (; i < wt; i++)
                        mbwrite.putInt(ls.get(i));
                } catch (Exception e) {
                    LogUtil.info("[WriteAdapter]", "[writeListInt]", e.getMessage());
                }
                return i;
            }
        };
    }
	
	/*public boolean exists()
	{
		return fl.exists();
	}
	
	public boolean isFile()
	{
		return fl.isFile();
	}
	
	public String getPath()
	{
		return fl.getPath();
	}
	
	
	public boolean delete()
	{
		close();
		boolean b = false;
		try{
			b = fl.delete();
		}catch(Exception e){
			System.out.println(e);
		}
		return b;
	}*/

    public int copyTo(String toFilePath) {
        return copyTo(toFilePath, FileAdapter.m(8));
    }

    public int copyTo(String toFilePath, long every) {
        int c = 0;
        FileAdapter fa = new FileAdapter(toFilePath);
        fa.createFile();
        byte[] bts = null;
        long begin = 0;
        while ((bts = this.getReader(begin, every).readAll()) != null) {
            c += fa.getWriter().write(bts);
            begin += bts.length;
        }
        fa.close();
        return c;
    }

    public Result<Integer> tryCopyTo(String toFilePath) {
        return tryCopyTo(toFilePath, FileAdapter.m(8));
    }

    public Result<Integer> tryCopyTo(final String toFilePath, final long every) {
        final FileResult<Integer> fr = new FileResult<>(false);
        PoolExector.tpe().execute(new Runnable() {
            public void run() {
                try {
                    int bl = copyTo(toFilePath, every);
                    fr.setResult(bl);
                    fr.setReady(FileResult.READY);
                } catch (Throwable e) {
                    LogUtil.info("tryCopyFile", "exception", e);
                    fr.setReady(FileResult.EXCEPTION);
                }
            }
        });
        return fr;
    }

    public final void closeBuffer(final Buffer buffer) {
        if (null == buffer)
            return;
        AccessController.doPrivileged(new PrivilegedAction<Object>() {
            public Object run() {
                try {
                    Method cleanerMethod = buffer.getClass().getMethod("cleaner");
                    if (null == cleanerMethod)
                        return null;
                    cleanerMethod.setAccessible(true);
                    Object cleanerObj = cleanerMethod.invoke(buffer);
                    if (null == cleanerObj)
                        return null;
                    Method cleanMethod = cleanerObj.getClass().getMethod("clean");
                    if (null == cleanMethod)
                        return null;
                    cleanMethod.invoke(cleanerObj);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
                return null;
            }
        });
    }

    public void closeExit() {
        PoolExector.close();
        close();
    }

    public void close() {
        try {
            if (fc != null) fc.close();
            if (raf != null) raf.close();
            closeBuffer(mbread);
            closeBuffer(mbwrite);
        } catch (Exception e) {
            LogUtil.info("[FileAdapter]", "[close]", e.getMessage());
        }
    }

    public static void main(String[] args) {
    }
}